﻿#region

using System.Linq.Expressions;
using SqlSugar;
using Vin.Extension.Framework.Dto;
using Vin.Extension.Framework.Entities;
using Vin.Extension.Framework.SugarFilter;
using Vin.Extension.SqlSugar.SugarFilter;
using Vin.Tool.Core.BasicTypeCategory;

#endregion

namespace Vin.Extension.Framework.Extension;

public static class SugarQueryableExtension
{
    #region 根据表达式获取字段名

    /// <summary>
    /// 根据表达式获取字段名
    /// </summary>
    /// <param name="expression"></param>
    /// <param name="singleNeedPrefix"></param>
    /// <returns></returns>
    private static string GetFieldName(LambdaExpression expression, bool singleNeedPrefix = false)
    {
        var body = expression.Body as MemberExpression;
        var fieldName = body!.Member.Name.ToUnderLine();

        if (expression.Parameters.Count > 1 || singleNeedPrefix)
        {
            fieldName = $"{(body.Expression as ParameterExpression)?.Name}.{fieldName}";
        }

        return fieldName!;
    }

    #endregion

    #region 分页查询

    /// <summary>
    /// 分页查询
    /// </summary>
    /// <param name="queryable"></param>
    /// <param name="dto"></param>
    /// <param name="timeFieldName">时间范围的字段名</param>
    /// <param name="orderByExpression"></param>
    /// <param name="orderByType"></param>
    /// <typeparam name="T"></typeparam>
    /// <typeparam name="TF"></typeparam>
    /// <returns></returns>
    public static async Task<List<T>> ToPageListAsync<T, TF>(this ISugarQueryable<T> queryable, TF dto,
        string timeFieldName = nameof(VinBaseEntity.CreateTime),
        Expression<Func<T, object?>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc,
        bool notPage = false, bool enableOrder = true)
        where T : VinBaseEntity
        where TF : VinFrameworkBaseListDto
    {
        timeFieldName = !timeFieldName.Contains('_') ? timeFieldName.ToUnderLine()! : timeFieldName;
        return await queryable.ToObjectPageListAsync(dto, timeFieldName, orderByExpression, orderByType, notPage,
            enableOrder);
    }

    public static async Task<List<T>> ToPageListRecordAsync<T, TF>(this ISugarQueryable<T> queryable, TF dto,
        string timeFieldName = nameof(VinBaseEntity.CreateTime),
        Expression<Func<T, object?>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc,
        bool notPage = false, bool enableOrder = true)
        where T : VinBaseRecordEntity
        where TF : VinFrameworkBaseListDto
    {
        timeFieldName = !timeFieldName.Contains('_') ? timeFieldName.ToUnderLine()! : timeFieldName;
        return await queryable.ToObjectPageListAsync(dto, timeFieldName, orderByExpression, orderByType, notPage,
            enableOrder);
    }

    public static async Task<List<T>> ToPageListAsync<T, TF>(this ISugarQueryable<T> queryable, TF dto,
        Expression<Func<T, DateTime?>> timeFieldNameExpression, bool needPrefix = false,
        Expression<Func<T, object?>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc,
        bool notPage = false, bool enableOrder = true)
        where T : VinBaseEntity
        where TF : VinFrameworkBaseListDto
    {
        return await ToPageListAsync(queryable, dto, GetFieldName(timeFieldNameExpression, needPrefix),
            orderByExpression, orderByType, notPage, enableOrder);
    }

    public static async Task<List<T>> ToPageListRecordAsync<T, TF>(this ISugarQueryable<T> queryable, TF dto,
        Expression<Func<T, DateTime?>> timeFieldNameExpression, bool needPrefix = false,
        Expression<Func<T, object?>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc,
        bool notPage = false, bool enableOrder = true)
        where T : VinBaseRecordEntity
        where TF : VinFrameworkBaseListDto
    {
        return await ToPageListRecordAsync(queryable, dto, GetFieldName(timeFieldNameExpression, needPrefix),
            orderByExpression, orderByType, notPage, enableOrder);
    }

    public static async Task<List<T>> ToPageListAsync<T, T2, TF>(this ISugarQueryable<T, T2> queryable, TF dto,
        Expression<Func<T, T2, DateTime?>> timeFieldNameExpression,
        Expression<Func<T, object?>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc,
        bool notPage = false, bool enableOrder = true)
        where T : VinBaseEntity
        where TF : VinFrameworkBaseListDto
    {
        return await ToPageListAsync(queryable, dto, GetFieldName(timeFieldNameExpression), orderByExpression,
            orderByType, notPage, enableOrder);
    }

    public static async Task<List<T>> ToObjectPageListAsync<T, TF>(this ISugarQueryable<T> queryable, TF dto,
        Expression<Func<T, DateTime?>> timeFieldNameExpression, bool needPrefix = false,
        Expression<Func<T, object?>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc,
        bool notPage = false, bool enableOrder = true)
        where TF : VinFrameworkBaseListDto
    {
        return await ToObjectPageListAsync(queryable, dto, GetFieldName(timeFieldNameExpression, needPrefix),
            orderByExpression, orderByType, notPage, enableOrder);
    }

    public static async Task<List<T>> ToObjectPageListAsync<T, TF>(this ISugarQueryable<T> queryable, TF dto,
        string timeFieldName = nameof(VinBaseEntity.CreateTime),
        Expression<Func<T, object?>>? orderByExpression = null, OrderByType orderByType = OrderByType.Desc,
        bool notPage = false, bool enableOrder = true)
        where TF : VinFrameworkBaseListDto
    {
        var conditionalModels = new List<IConditionalModel>();
        if (dto.StartTime.HasValue)
        {
            conditionalModels.Add(new ConditionalModel()
            {
                FieldName = timeFieldName,
                ConditionalType = ConditionalType.GreaterThanOrEqual,
                FieldValue = dto.StartTime.Value.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }

        if (dto.EndTime.HasValue)
        {
            conditionalModels.Add(new ConditionalModel()
            {
                FieldName = timeFieldName,
                ConditionalType = ConditionalType.LessThanOrEqual,
                FieldValue = dto.EndTime.Value.ToString("yyyy-MM-dd HH:mm:ss")
            });
        }

        if (conditionalModels.Count > 0)
        {
            queryable = queryable.Where(conditionalModels);
        }

        if (enableOrder)
        {
            queryable = orderByExpression != null
                ? queryable.OrderBy(orderByExpression, orderByType)
                : queryable.OrderByPropertyName($"{timeFieldName}", orderByType);
        }

        notPage = dto.NotPage ?? notPage;
        if (notPage)
        {
            return await queryable.ToListAsync();
        }

        return await queryable.ToPageListAsync(dto.Page, dto.PageSize, dto.RefTotal);
    }

    #endregion

    #region 删除或启用 IDeleted, IEnabled

    public static ISugarQueryable<T> ClearDeleted<T>(this ISugarQueryable<T> queryable) where T : IDeleted
    {
        return queryable.ClearFilter<IDeleted>();
    }

    public static ISugarQueryable<T> ClearEnabled<T>(this ISugarQueryable<T> queryable) where T : IEnabled
    {
        return queryable.ClearFilter<IEnabled>();
    }

    public static ISugarQueryable<T> AddEnabled<T>(this ISugarQueryable<T> queryable, bool isEnabled = true)
        where T : IEnabled
    {
        queryable.Context.QueryFilter.AddTableFilter<IEnabled>(m => m.IsEnabled == isEnabled);
        return queryable;
    }

    #endregion
}